From 7d1b081dcb1b4616307e871e760d6a080d843856 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20H=C3=A4rdeman?= Date: Fri, 10 Oct 2025 19:55:36 +0200 Subject: [PATCH] dhcpv4: lazy store statefiles MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Currently, the dhcpv4 server saves the statefile on every change and also calls the leasetrigger script every time the statefile is updated (which triggers a dnsmasq reload). In addition, odhcpd wakes up every second (see dhcpv4_valid_until_cb()) to go through all existing leases to see if any lease has expired. With this change, the wakeups are reduced to every 5 seconds, and the statefile is only written (if necessary) during that wakeup. Before this change (without any leasetrigger, test on my laptop, not a real OpenWrt device): $ time sudo ./build/dhcpdig -4 benchmark foo-client Thread[**]: req 10000101/0 rel 10000101/0 rep 10000101/0 real 55m29.406s user 0m0.005s sys 0m0.010s (This is a simple benchmark tool I wrote, it runs 10 threads which divide the DHVPv4 pool into 10 chunks and then performs 1 million random addr req/release per thread in a loop). After this change: $ time sudo ./build/dhcpdig -4 benchmark foo-client Thread[**]: req 10000101/0 rel 10000101/0 rep 10000101/0 real 1m48.123s user 0m0.005s sys 0m0.005s A 3082% speedup. Signed-off-by: David Härdeman Link: https://github.com/openwrt/odhcpd/pull/298 Signed-off-by: Álvaro Fernández Rojas --- src/config.c | 1 + src/dhcpv4.c | 23 +++++++++++++++++++++-- src/odhcpd.h | 1 + 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/config.c b/src/config.c index 63e3952..6917f9a 100644 --- a/src/config.c +++ b/src/config.c @@ -344,6 +344,7 @@ static void set_interface_defaults(struct interface *iface) iface->ra_lifetime = 3 * iface->ra_maxinterval; /* RFC4861: AdvDefaultLifetime: Default: 3 * MaxRtrAdvInterval */ iface->ra_dns = true; iface->pio_update = false; + iface->update_statefile = true; } static void clean_interface(struct interface *iface) diff --git a/src/dhcpv4.c b/src/dhcpv4.c index aaf6821..d5177c6 100644 --- a/src/dhcpv4.c +++ b/src/dhcpv4.c @@ -336,6 +336,9 @@ void dhcpv4_free_lease(struct dhcpv4_lease *lease) if (lease->fr_ip) dhcpv4_fr_stop(lease); + if (lease->iface) + lease->iface->update_statefile = true; + list_del(&lease->head); if (lease->lease_cfg) lease->lease_cfg->dhcpv4_lease = NULL; @@ -407,6 +410,8 @@ static bool dhcpv4_assign(struct interface *iface, struct dhcpv4_lease *lease, debug("Assigned static IP address: %s", inet_ntop(AF_INET, &lease->addr, ipv4_str, sizeof(ipv4_str))); + + iface->update_statefile = true; return true; } @@ -423,6 +428,7 @@ static bool dhcpv4_assign(struct interface *iface, struct dhcpv4_lease *lease, } else { debug("Assigned the requested IP address: %s", inet_ntop(AF_INET, &lease->addr, ipv4_str, sizeof(ipv4_str))); + iface->update_statefile = true; return true; } @@ -448,6 +454,8 @@ static bool dhcpv4_assign(struct interface *iface, struct dhcpv4_lease *lease, debug("Assigned IP adress from pool: %s (succeeded on attempt %u of %u)", inet_ntop(AF_INET, &lease->addr, ipv4_str, sizeof(ipv4_str)), i + 1, count); + + iface->update_statefile = true; return true; } } @@ -624,7 +632,7 @@ dhcpv4_lease(struct interface *iface, enum dhcpv4_msg req_msg, const uint8_t *re return NULL; } - dhcpv6_ia_write_statefile(); + iface->update_statefile = true; return lease; } @@ -1498,6 +1506,7 @@ static void dhcpv4_valid_until_cb(struct uloop_timeout *event) { struct interface *iface; time_t now = odhcpd_time(); + bool update_statefile = false; avl_for_each_element(&interfaces, iface, avl) { struct dhcpv4_lease *lease, *tmp; @@ -1511,10 +1520,20 @@ static void dhcpv4_valid_until_cb(struct uloop_timeout *event) (struct in_addr *)&lease->addr, lease->hostname, iface->ifname); dhcpv4_free_lease(lease); + update_statefile = true; } } + + if (iface->update_statefile) { + update_statefile = true; + iface->update_statefile = false; + } } - uloop_timeout_set(event, 1000); + + if (update_statefile) + dhcpv6_ia_write_statefile(); + + uloop_timeout_set(event, 5000); } /* Create socket and register events */ diff --git a/src/odhcpd.h b/src/odhcpd.h index 41c0099..2682e44 100644 --- a/src/odhcpd.h +++ b/src/odhcpd.h @@ -338,6 +338,7 @@ struct interface { char *ifname; const char *name; uint32_t if_mtu; + bool update_statefile; // IPv6 runtime data struct odhcpd_ipaddr *addr6; -- 2.30.2